/************************************************************************************************************************/

/* Distintos tipo que se pueden declarar*/
declaracion			:	declaracion_ulongint ';' {$$ = $1; yyout("declaracion<-declaracion_ulongint: $$ = $1"+"-->"+$1.lista.toString());}
				|       declaracion_uinteger ';' {$$ = $1; yyout("declaracion<-declaracion_uinteger: $$ = $1"+"-->"+$1.lista.toString());}
				|	tipo_estructura ';' {$$ = $1; yyout("declaracion<-tipo_estructura: $$ = $1"+"-->"+$1.lista.toString());}
				|	IDENTIFICADOR declaracion_estructura ';' {yyout("Declaracion de variables del tipo ESTRUCTURA " + $1.elemento_token.getCadena());
					    
					//Ver que exista la definicion del la estructura con ese nombre en la tabla de simbolos, si no error
					    if (!(this.ts.existeToken($1.elemento_token.getCadena()) )){
						yyerror ("Warning: Tipo STRUCT: " + $1.elemento_token.getCadena() + "no declarado" );
					    }else{
						
						  //Crear uno nuevo y clonarlo!!! al tipo de la tabla con el nombre de estructura nombreIdentificador
						  
		
					    };
					String nombreIdentificador = $1.elemento_token.getCadena();
					
					if ((this.ts.existeToken(nombreIdentificador) )&&(this.ts.get(nombreIdentificador).getId().equals(Tokens.rsv_struct))){
					    
					    //Crear uno nuevo y clonarlo!!! al tipo de la tabla con el nombre de estructura nombreIdentificador
	
					    for(Iterator it = $2.lista.iterator();it.hasNext();){
						    
						Token tipoEstructura = (Token_Struct)((Token_Struct)this.ts.get(nombreIdentificador)).clone();
						Token e = (Token) it.next();
						tipoEstructura.setCadena(e.getCadena());
						tipoEstructura.setPadre((Token_Identificador)this.ts.get(nombreIdentificador));
						this.ts.set(tipoEstructura);
						}
		
		
					    }else{
						  
						yyerror ("Warning: Tipo STRUCT: " + nombreIdentificador + "no declarado" );					
	
						};

/*************************************************************************************************************************/					

/* Declaracion de un ULONGINT, ej: ULONGINT a,b,c; */
declaracion_ulongint            :	ULONGINT IDENTIFICADOR {yyout("Declaracion ULONGINT");

					    //Obtengo el nombre la cadena del Identificador que va a ser el nombre de la Variable UInteger
					    String nombreIdentificador = $2.elemento_token.getCadena();
					    
					    //Creo un entero del tipo correspondiente
					    Token entero = new Token_Ulongint();
					    
					    //Creo variable con el nombre Identificador y un tipo entero sin valor, dado que no fue ahun asignado
					    Token variable = new Token_Variable(nombreIdentificador, entero);
					    
					    //Actualizo la tabla de simbolos
					    this.ts.set(variable);
					    
					    //Agrego en una lista de elementos auxiliar...
					    ArrayList listaTokens = new ArrayList();
					    listaTokens.add(variable);
					    
					    //La Izquierdo sevuelve lado derecho...
					    $$ = new ParserVal(listaTokens);
				}

				|	declaracion_ulongint ',' IDENTIFICADOR {yyout("Declaracion ULONGINT");

					    //Obtengo el nombre la cadena del Identificador que va a ser el nombre de la Variable UInteger
					    String nombreIdentificador = $3.elemento_token.getCadena();
					    
					    //Creo un entero del tipo correspondiente
					    Token entero = new Token_Ulongint();
					    
					    //Creo variable con el nombre Identificador y un tipo entero sin valor, dado que no fue ahun asignado
					    Token variable = new Token_Variable(nombreIdentificador, entero);
					    
					    //Actualizo la tabla de simbolos
					    this.ts.set(variable);
					    
					    //Obtengo la lista y agrego el nuevo elemento...
					    boolean add = $1.lista.add(variable);
					    
					    //El no terminal Izquierdo se vuevle los elementos del derecho...
					    $$ = $1;

				}

/***********************************************************************************************************************/

/*Declaracion de variables de un tipo estructura ej: Pepe p1,p2; */
declaracion_estructura		:	IDENTIFICADOR 

					{ //Agrego en una lista de elementos auxiliar...
					    ArrayList listaTokens = new ArrayList();
					    listaTokens.add($1);
					    
					  //La Izquierdo se vuelve lado derecho...
					    $$ = new ParserVal(listaTokens);
					}

				|	declaracion_estructura ',' IDENTIFICADOR
					{
					$1.lista.add($3);
					$$ = $1; yyout ("declaracion_estrucutura <- declaracion_estructura , IDENTIFICADOR" + $1 + $3);
					}
				;

/**********************************************************************************************************************/

* Seleccion IF (condicion) THEN bloque ELSE bloque todos con presencia oblgatoria */

seleccion		:	IF condicion /* HH Polaca.apilar(+1) */ {P.apilar(P.posActual()+1);} THEN  {yyout("--- Seleccion IF ---");} seleccion_else 
				|	IF condicion {yyout("--- Seleccion IF ---"); yyerror("Seleccion: Se esperaba THEN luego de condicion");} seleccion_else
				|	IF error {yyerror("Seleccion: se esperaba condicion luego de palabra reservada IF");}
				;

seleccion_else	:	bloque /* HH int posicionFinThen:= Polaca.desapilar()+3; Polaca.escribir(posicionFinThen, New Token Uint(posicionFinThen); Polaca.apilar(+1); */
					      {
						int posicionPrincipioELSE = P.posActual()+3; P.escribir((int)P.desapilar(), new Token_Pos(posicionPrincipioELSE)); P.apilar(P.posActual()+1); 
						P.addElemento(new Token_Pos(-1)); P.addElemento(new Token (Tokens.salto_incondicional)); 
						//P.setPosicionmenos1();	P.setPosicionmenos1();
					      }						
					ELSE {yyout("--- Seleccion ELSE ---");} seleccion_fin

				|	ELSE {yyout("--- Seleccion ELSE ---"); yyerror("Seleccion: se esperaba bloque luego de condicion");}
				|	bloque error {yyout("--- Fin de seleccion ---"); yyerror("Seleccion: se esperaba palabra reservada ELSE luego de bloque");}
				|	error {yyout("--- Fin de seleccion ---"); yyerror("Seleccion: se esperaba bloque luego de condicion");}
				;

seleccion_fin			:	bloque {yyout("--- Fin de seleccion ---");
						/* HH int posicionFinIFELSE:= Polaca.desapilar()+1; Polaca.escribir(posicion,New Token_Pos(posicion)) */
						int posicionFinIFELSE = P.posActual()+1;
						P.escribir((int)P.desapilar(),new Token_Pos(posicionFinIDELSE));
					       }
 
				|	error {yyout("--- Fin de seleccion ---"); yyerror("Seleccion: se esperaba bloque luego de palabra reservada ELSE");}
				;
/***********************************************************************************************************************/

/* Expresiones Aritmeticas */
expresion			:	termino
				|	expresion '+' termino {
								//HH Crear un Token + Polaca.escribir(Token +)
								P.addElemento (new Token_OperadorSuma());								
							      }
				|	expresion '-' termino {
								//HH Crear un Token - Polaca.escribir(Token -)
							        P.addElemento (new Token_OperadorResta());
							      }
				|	expresion '+' error {yyerror("Expresion: se esperaba un termino luego de \"+\"");}
				|	expresion '-' error {yyerror("Expresion: se esperaba un termino luego de \"-\"");}
				;

termino				:	factor
				|	termino '*' factor {
							    //HH Crear un Token * y Polaca.escribir(Token *)
							    P.addElemento (new Token_OperadorMul());
							   }
				|	termino '/' factor {
							    //HH Crear un Token / y Polaca.escribir(Token /)
							    P.addElemento (new Token_OperadorDiv());
							   }

				|	termino '*' error {yyerror("Termino: se esperaba un factor luego de \"*\"");}
				|	termino '/' error {yyerror("Termino: se esperaba un factor luego de \"/\"");}
				;

factor				:	IDENTIFICADOR {
							//HH Polaca.escribir(Token IDENTIFICADOR) 
							P.addElemento ($1);
						      }
				|	constante {
							//HH Polaca.escribir(Token constante)
							P.addElemento ($1);
						  }
/****************************************************************************************************************************/
/* Acceso elemento estructura */
elemento_estructura		:	IDENTIFICADOR '.' campo_estructura //HH Crear un Token '.' Polaca.escribir(Token ID), Polaca.escribir(Token campo_estr) 
				;

constante			:	CONST_UL { $$ = $1;}
				|	CONST_UI { $$ = $1;}
				;


/* Condicion Logica */
condicion			:	'(' expresion operador_logico expresion ')' 	{ 
											P.addElemento (new Token_Cmp());
											P.addElemento (new Token_Pos(-1));
											P.addElemento ($3);
											//P.setPosicionmenos1();
											//P.setPosicionmenos1();
											}
				|	expresion operador_logico expresion {yyerror("Condicion: se esperaba \"(\" y \")\"");}
				|	'{' expresion operador_logico expresion '}' {yyerror("Condicion: se esperaba \"(\" y \")\" en lugar de \"{\" y \"}\"");}
				|	'(' expresion operador_logico expresion error {yyerror("Condicion: se esperaba \")\" luego de expresion");}
				|	'(' expresion operador_logico error {yyerror("Condicion: se esperaba expresion luego de operador logico");}
				|	'(' expresion error {yyerror("Condicion: se esperaba operador logico");}
				|	'(' error ')' {yyerror("Condicion: condicon logica no valida");}
                                ;
/*Operador Logico*/
operador_logico			:	'>' {$$ = new Token(Tokens.menor_igual);}
				|	'<' {$$ = new Token(Tokens.mayor_igual);}
				|	'=' {$$ = new Token(Tokens.distinto);}
				|	MAYOR_IGUAL {$$ = new Token(Tokens.menor);}
				|	MENOR_IGUAL {$$ = new Token(Tokens.mayor);}
				|	DIFERENTE {$$ = new Token(Tokens.igual);}
				;
/****************************************************************************************************************************/
TSimbolo ts;		// Tabla de Simbolos
Polaca P;            	// Polaca

